1 module hip.systems.gamepads.xbox;
2 import hip.util.system;
3 import hip.systems.gamepad;
4 
5 ///Refer to https://docs.microsoft.com/en-us/uwp/api/windows.gaming.input.gamepadbuttons?view=winrt-20348
6 enum HipXboxGamepadButton : int
7 {
8     none            = 0,     ///No button.
9     menu            = 1,     ///Menu button.
10     view            = 1<<1,  ///View button.
11     a               = 1<<2,  ///A button.
12     b               = 1<<3,  ///B button.
13     x               = 1<<4,  ///X button.
14     y               = 1<<5,  ///Y button.
15     dPadUp          = 1<<6,  ///D-pad up.
16     dPadDown        = 1<<7,  ///D-pad down.
17     dPadLeft        = 1<<8,  ///D-pad left.
18     dPadRight       = 1<<9,  ///D-pad right.
19     leftShoulder    = 1<<10, ///Left bumper.
20     rightShoulder   = 1<<11, ///Right bumper.
21     leftThumbstick  = 1<<12, ///Left stick.
22     rightThumbstick = 1<<13, ///Right stick.
23     paddle1         = 1<<14, ///The first paddle.
24     paddle2         = 1<<15, ///The second paddle.
25     paddle3         = 1<<16, ///The third paddle.
26     paddle4         = 1<<17, ///The fourth paddle.
27 }
28 
29 
30 pragma(inline, true) 
31 bool isXboxGamepadButtonPressed(int gamepadState, HipXboxGamepadButton btn){return (gamepadState & btn) == btn;}
32 
33 struct HipInputXboxGamepadState
34 {
35     int buttons;
36     double leftAnalogX;
37     double leftAnalogY;
38     double rightAnalogX;
39     double rightAnalogY;
40     double leftTrigger;
41     double rightTrigger;
42 }
43 
44 
45 //////// External API ////////
46 extern(System) __gshared
47 {
48     ubyte* function() HipGamepadCheckConnectedGamepads;
49     HipGamepadBatteryStatus function(ubyte id) HipGamepadGetBatteryStatus;
50     HipInputXboxGamepadState function(ubyte id) HipGamepadGetXboxGamepadState;
51     bool function(ubyte id) HipGamepadIsWireless;
52     ubyte function() HipGamepadQueryConnectedGamepadsCount;
53 
54     void function(
55         ubyte id,
56         double leftMotor,
57         double rightMotor,
58         double leftTrigger,
59         double rightTrigger
60     ) HipGamepadSetXboxGamepadVibration;
61 }
62 
63 
64 
65 extern(D):
66 void initXboxGamepadInput()
67 {
68     __gshared bool hasInit = false;
69     if(hasInit)
70         return;
71     version(Windows)
72     {
73         string[] errors = dllImportVariables!(
74             HipGamepadCheckConnectedGamepads,
75             HipGamepadGetBatteryStatus,
76             HipGamepadGetXboxGamepadState,
77             HipGamepadIsWireless,
78             HipGamepadQueryConnectedGamepadsCount,
79             HipGamepadSetXboxGamepadVibration
80         );
81         foreach(err; errors)
82         {
83             import hip.console.log;
84             logln("HIPREME_ENGINE: Could not load ", err);
85         }
86     }
87 
88     hasInit = true;
89 }
90 
91 //////// End External API ////////
92 
93 /** Engine task:
94 * Send gamepad connect and disconnect events
95 * Poll every connected gamepad every frame
96 * Should always return a neutral state for every disconnected gamepad
97 *
98 * Game task:
99 * Check gamepad count
100 * Decide what will do with connected gamepads
101 */
102 class HipXBOXGamepad : IHipGamepadImpl
103 {
104     void poll(HipGamepad pad)
105     {
106         HipInputXboxGamepadState state = HipGamepadGetXboxGamepadState(pad.getId);
107         int b = state.buttons;
108         with(pad)
109         {
110             setAnalog(HipGamepadAnalogs.leftStick, [state.leftAnalogX, state.leftAnalogY, 1]);
111             setAnalog(HipGamepadAnalogs.rightStick, [state.rightAnalogX, state.rightAnalogY, 1]);
112 
113             leftTrigger = state.leftTrigger;
114             rightTrigger = state.rightTrigger;
115             setButtonPressed(HipGamepadButton.xboxY, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.y));
116             setButtonPressed(HipGamepadButton.xboxX, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.x));
117             setButtonPressed(HipGamepadButton.xboxA, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.a));
118             setButtonPressed(HipGamepadButton.xboxB, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.b));
119 
120             setButtonPressed(HipGamepadButton.dPadUp, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadUp));
121             setButtonPressed(HipGamepadButton.dPadLeft, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadLeft));
122             setButtonPressed(HipGamepadButton.dPadDown, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadDown));
123             setButtonPressed(HipGamepadButton.dPadRight, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadRight));
124 
125             setButtonPressed(HipGamepadButton.left1, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.leftShoulder));
126             setButtonPressed(HipGamepadButton.right1, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.rightShoulder));
127             // setButtonPressed(HipGamepadButton.left2, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.pa));
128             // setButtonPressed(HipGamepadButton.right2, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadRight));
129 
130             setButtonPressed(HipGamepadButton.left3, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.leftThumbstick));
131             setButtonPressed(HipGamepadButton.right3, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.rightThumbstick));
132 
133             setButtonPressed(HipGamepadButton.start, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.menu));
134             setButtonPressed(HipGamepadButton.select, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.view));
135         }
136     }
137 
138     void setVibrating(ubyte id, double leftMotor, double rightMotor, double leftTrigger, double rightTrigger)
139     {
140         HipGamepadSetXboxGamepadVibration(id, 
141             leftMotor,
142             rightMotor,
143             leftTrigger,
144             rightTrigger
145         );
146     }
147     bool isWireless(ubyte id){return HipGamepadIsWireless(id);}
148     HipGamepadBatteryStatus getBatteryStatus(ubyte id){return HipGamepadGetBatteryStatus(id);}
149 }